package cn.wing.event;

import cn.wing.constant.GuiConstant;
import cn.wing.gui.TradingMenu;
import cn.wing.saveddata.TransactionInfoData;
import cn.wing.utils.TransactionInfo;
import net.minecraft.client.Minecraft;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.fml.LogicalSide;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.PacketDistributor;

import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;

import static cn.wing.PlayTradingMain.TRANSACTION_INFO_MAP_CHANNEL;

public class TransactionInfoMapSync {
    String uuid;
    TransactionInfo transactionInfo;

    public TransactionInfoMapSync(String uuid, TransactionInfo transactionInfo) {
        this.uuid = uuid;
        this.transactionInfo = transactionInfo;
    }

    public TransactionInfoMapSync setClear(boolean clear) {
        this.clear = clear;
        return this;
    }

    private boolean clear;

    public void encode(FriendlyByteBuf buf) {
        buf.writeBoolean(clear);
        if (clear) {
            return;
        }

        buf.writeUtf(uuid);
        if (transactionInfo == null) {
            buf.writeBoolean(false);
            return;
        }
        buf.writeBoolean(true);
        buf.writeUUID(transactionInfo.getPlayer());
        buf.writeItemStack(transactionInfo.getSellItemStack(), false);
        buf.writeInt(transactionInfo.getBuyItemStack().size());
        for (ItemStack itemStack : transactionInfo.getBuyItemStack()) {
            buf.writeItemStack(itemStack, false);
        }
        buf.writeUtf(transactionInfo.getNotes());
    }
    public static TransactionInfoMapSync decode(FriendlyByteBuf buf) {
        boolean clear2 = buf.readBoolean();
        if (clear2) {
            return new TransactionInfoMapSync(null, null).setClear(true);
        }
        String uuid = buf.readUtf();
        boolean b = buf.readBoolean();
        if (!b) {
            return new TransactionInfoMapSync(uuid, null);
        }
        UUID player = buf.readUUID();
        ItemStack sellItemStack = buf.readItem();
        int i = buf.readInt();
        ArrayList<ItemStack> itemStacks = new ArrayList<>();
        for (int j = 0; j < i; j++) {
            itemStacks.add(buf.readItem());
        }
        TransactionInfo transactionInfo1 = new TransactionInfo(player, sellItemStack, itemStacks, buf.readUtf());
        transactionInfo1.setUuid(uuid);
        return new TransactionInfoMapSync(uuid, transactionInfo1).setClear(clear2);
    }

    /* ---------- 统一处理器 ---------- */
    public static void handle(TransactionInfoMapSync pkt, Supplier<NetworkEvent.Context> ctx) {
        ctx.get().enqueueWork(() -> {

            // 判断方向
            LogicalSide side = ctx.get().getDirection().getReceptionSide();

            ServerPlayer sender = ctx.get().getSender();
            if (side == LogicalSide.SERVER && sender != null) {
                // 客户端→服务端：更新服务器 map 并广播
                HashMap<Integer, Integer> indexs = new HashMap<>();
                AtomicBoolean canPay = new AtomicBoolean(true);
                TradingMenu tradingMenu = (TradingMenu) sender.containerMenu;
                TransactionInfo payItem = GuiConstant.TRANSACTION_INFO_MAP.get(pkt.uuid);
                if (pkt.transactionInfo == null) {
                    List<ItemStack> buyItemStack = payItem.getBuyItemStack();
                    buyItemStack.forEach(v -> {
                        if (v.getCount() == 0) {
                            return;
                        }
                        if (canPay.get()) {
                            for (int i = 0; i < tradingMenu.slots.size(); i++) {
                                Slot slot = tradingMenu.slots.get(i);
                                    if (ItemStack.isSameItemSameTags(v, slot.getItem()) && v.getCount() < slot.getItem().getCount()) {
                                        indexs.put(i, v.getCount());
                                        return;
                                    }
                            }
                        }
                        canPay.set(false);
                    });
                }
                if (!canPay.get()) {
                    sender.sendSystemMessage(Component.literal("绿宝石不够购买"));
                    return;
                }
                Map<String, TransactionInfo> transactionInfoMap = GuiConstant.TRANSACTION_INFO_MAP;
                if (transactionInfoMap.containsKey(pkt.uuid)) {
                    MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer();
                    ServerPlayer player = server.getPlayerList().getPlayer(transactionInfoMap.get(pkt.uuid).getPlayer());
                    for (ItemStack itemStack : transactionInfoMap.get(pkt.uuid).getBuyItemStack()) {
                        player.getInventory().add(itemStack);
                    }

                    transactionInfoMap.remove(pkt.uuid);
                    tradingMenu.addItem(payItem.getSellItemStack().copy());
                    indexs.forEach(tradingMenu::clear);
                } else {
                    transactionInfoMap.put(pkt.uuid, pkt.transactionInfo);
                }

                // server -> client
                TRANSACTION_INFO_MAP_CHANNEL.send(PacketDistributor.ALL.noArg(), pkt);
                // save TRANSACTION_INFO_MAP
                TransactionInfoData.get(sender.serverLevel()).setDirty();
            } else {

                Minecraft mc = Minecraft.getInstance();
                if (!mc.isSingleplayer() && !mc.hasSingleplayerServer()) {
                    Map<String, TransactionInfo> transactionInfoMap = GuiConstant.TRANSACTION_INFO_MAP;
                    if (pkt.clear) {
                        GuiConstant.TRANSACTION_INFO_MAP.clear();
                    }
                    if (transactionInfoMap.containsKey(pkt.uuid)) {
                        transactionInfoMap.remove(pkt.uuid);
                    } else {
                        transactionInfoMap.put(pkt.uuid, pkt.transactionInfo);
                    }
                }
            }

        });
        ctx.get().setPacketHandled(true);
    }
}
